/**
 * Fleet.java
 *
 * Roslan's Remake of MOO in 3D using Ardor3D
 * (C) 2011 Roslan Amir. All rights reserved.
 */

package com.roslan.games.moo3d.data;

import java.util.Arrays;

/**
 * This class represents a single fleet for a race. Each ship type is represented as a counter for the number of ships of that
 * type in this fleet. The counter is an array of <code>int</code>s for each ship type.
 * 
 * @author Roslan Amir
 * @version 1.0 - Jan 16, 2011
 */
public class Fleet {

	/**
	 * Counter used to generate unique names for the <code>Fleet</code> instance.
	 */
	private static int counter;

	/**
	 * The name given to this <code>Fleet</code> instance.
	 */
	public final String name;

	/**
	 * An array of <code>int</code>s specifying the count for each ship type.
	 */
	public final int[] shipCount;

	/**
	 * The warp speed of the whole fleet. Equals to the warp speed of the slowest ship type in the fleet.
	 */
	public int warpSpeed;

	/**
	 * The maximum range of this fleet. Equals to the maximum range of the ship type with the smallest maximum range in the
	 * fleet.
	 */
	public int maxRange;

	/**
	 * The race who owns this fleet.
	 */
	public Race owner;

	/**
	 * Constructor. Return an new instance of the <code>Fleet</code> object. The name is automatically generated and cannot be
	 * changed.
	 */
	public Fleet() {
		name = "Fleet" + (++counter);
		shipCount = new int[ShipType.TYPE_COUNT]; // number of slots for the ship types
		warpSpeed = Integer.MAX_VALUE;
		maxRange = Integer.MAX_VALUE;
	}

	/**
	 * Copy the fields from the source fleet to this fleet.
	 * 
	 * @param sourceFleet - the source fleet to copy
	 */
	public void copy(Fleet sourceFleet) {
		for (int index = 0; index < shipCount.length; index++) {
			shipCount[index] = sourceFleet.shipCount[index];
		}
		warpSpeed = sourceFleet.warpSpeed;
		maxRange = sourceFleet.maxRange;
		owner = sourceFleet.owner;
	}

	/**
	 * Merge the source fleet into this fleet.
	 * 
	 * @param sourceFleet - the source fleet to merge
	 */
	public void add(Fleet sourceFleet) {
		warpSpeed = Integer.MAX_VALUE;
		maxRange = Integer.MAX_VALUE;
		for (int index = 0; index < ShipType.TYPE_COUNT; index++) {
			shipCount[index] += sourceFleet.shipCount[index];
			if (shipCount[index] > 0) {
				ShipType shipType = owner.shipTypes[index];
				if (warpSpeed > shipType.warpSpeed) {
					warpSpeed = shipType.warpSpeed;
				}
				if (maxRange > shipType.maxRange) {
					maxRange = shipType.maxRange;
				}
			}
		}
	}

	/**
	 * Subtract the number of ships from this fleet specified by the source fleet.
	 * 
	 * @param sourceFleet - the source fleet to subtract
	 */
	public void subtract(Fleet sourceFleet) {
		warpSpeed = Integer.MAX_VALUE;
		maxRange = Integer.MAX_VALUE;
		for (int index = 0; index < ShipType.TYPE_COUNT; index++) {
			shipCount[index] -= sourceFleet.shipCount[index];
			if (shipCount[index] > 0) {
				ShipType shipType = owner.shipTypes[index];
				if (warpSpeed > shipType.warpSpeed) {
					warpSpeed = shipType.warpSpeed;
				}
				if (maxRange > shipType.maxRange) {
					maxRange = shipType.maxRange;
				}
			}
		}
	}

	/**
	 * Add <code>count</code> ships of the given type to the fleet. If these are the first ships of this type, the speed and
	 * range of the entire fleet may change. The fleet speed is the of the slowest ship type and the fleet max range is of the
	 * shortest ship type.
	 * 
	 * @param slot - the ship type slot (0-5)
	 * @param count - the number of ships to add
	 * @return <code>true</code> if the speed or range is changed; <code>false</code> otherwise
	 */
	public boolean addShips(int slot, int count) {
		boolean changed = false;
		shipCount[slot] += count;
		if (shipCount[slot] == count) { // new type added
			ShipType shipType = owner.shipTypes[slot];
			if (shipType.warpSpeed < this.warpSpeed) {
				this.warpSpeed = shipType.warpSpeed;
				changed = true;
			}
			if (shipType.maxRange < this.maxRange) {
				this.maxRange = shipType.maxRange;
				changed = true;
			}
		}
		return changed;
	}

	/**
	 * Subtract <code>count</code> ships of the given type from the fleet. Recalculate the maximum warp speed and maximum range
	 * of the fleet if all ships of the given type were removed.
	 * 
	 * @param slot - the ship type slot (0-5)
	 * @return <code>true</code> if the speed or range is changed; <code>false</code> otherwise
	 */
	public boolean subtractShips(int slot, int count) {
		boolean changed = false;
		shipCount[slot] -= count;
		if (shipCount[slot] == 0) {
			int speed = Integer.MAX_VALUE;
			int range = Integer.MAX_VALUE;
			for (int i = 0; i < ShipType.TYPE_COUNT; i++) {
				if (shipCount[i] > 0) {
					ShipType shipType = owner.shipTypes[i];
					if (speed > shipType.warpSpeed)
						speed = shipType.warpSpeed;
					if (range > shipType.maxRange)
						range = shipType.maxRange;
				}
			}
			if (warpSpeed != speed) {
				warpSpeed = speed;
				changed = true;
			}
			if (maxRange != range) {
				maxRange = range;
				changed = true;
			}
		}
		return changed;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Fleet [name=" + name + ", shipCount=" + Arrays.toString(shipCount) + ", warpSpeed=" + warpSpeed + ", maxRange=" + maxRange + ", owner=" + owner + "]";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return name.hashCode();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Fleet that = (Fleet) obj;
		return shipCount[0] == that.shipCount[0] && shipCount[1] == that.shipCount[1] && shipCount[2] == that.shipCount[2] && shipCount[3] == that.shipCount[3] && shipCount[4] == that.shipCount[4] && shipCount[5] == that.shipCount[5];
	}

}
